package com.foreveross.crawl.adapter.sub.impl20140402.v3;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.foreveross.crawl.adapter.AbstractAdapter;
import com.foreveross.crawl.adapter.PlaneInfoEntityBuilder;
import com.foreveross.crawl.common.PlaneInfoCommon;
import com.foreveross.crawl.common.exception.self.IpBlockException;
import com.foreveross.crawl.common.util.RegHtmlUtil;
import com.foreveross.crawl.domain.airfreight.AbstractPlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.CabinEntity;
import com.foreveross.crawl.domain.airfreight.TransitEntity;
import com.foreveross.crawl.domain.airfreight.doub.CabinRelationEntity;
import com.foreveross.crawl.domain.airfreight.doub.DoublePlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnCabinEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnDoublePlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnTransitEntity;
import com.foreveross.crawl.domain.airfreight.single.SinglePlaneInfoEntity;
import com.foreveross.crawl.exception.FlightInfoNotFoundException;
import com.foreveross.crawl.util.DateUtil;
import com.foreveross.crawl.util.StringUtil;
import com.foreveross.taskservice.common.bean.TaskModel;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * 大韩航空
 *1 大韩航空适配器，发现选有些城市，比如北京到东京，首页会有票价类别(舱位)的选择，如果是选非洲等某些国家，会没有票价的选择
 *2 有票价类型选择时选择头等舱进去和其他票价参数会有点差别，而且选择了头等舱到航班页面之后还会有票价的选择，里面包含了经济舱等
 *3有些航班号在经济舱和头等舱时应该是一样的，但是经济舱会省略中间的0，比如头等舱显示KE002，而经济舱显示KE2
 *4经济舱包含了经济舱特价的价格和航班 
 * 
 * @author stub
 * 
 */
public class KoreanAirAdapter_bak_1 extends AbstractAdapter {

	// 航班请求页地址
	private static final String cnHomeUrl = "http://www.koreanair.com/index_cn_chn.jsp";
	private static final String tranUrl = "http://www.koreanair.com/global/bl/rs/rs_v9reservationController.jsp";
	private static final String encUrl = "http://www.koreanair.com/global/bl/rs/tripflow_log_enct_xwkc.jsp";
	private static final String flightUrl = "http://wftc3.e-travel.com/plnext/KEREG/Override.action";
	
	//普通请求尝试次数
	private static final int geneRepeatTime = 3;
	//ip被封关键字
	private static final String swapIpRegex = "[\\s\\S]{0,1000}down1\\.htm[\\s\\S]{0,1000}";
	//请求航班页尝试次数
	private static final int queryPriceTime = 3;
	//选择头等舱请求航班页舱室次数 选择头等舱的第二页没价格
	private static final int queryFPriceTime = 3;
	
	private static final String carrierKey = "KE";	
	private static final String carrierName= "大韩航空";	
	private static final String carrierFullName= "大韩航空公司";	
	
	private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
	
	//航班号-对应实体 去除重复的航班用
	private Map<String,AbstractPlaneInfoEntity> entityMap = Maps.newHashMap();
	
	//去程航班号-舱位实体组 针对往返程的去程舱位，往返程的去程舱位去重
	private Map<String,List<String>> cabinMap = Maps.newHashMap();
	private Map<String,String> cabinIdMap = Maps.newHashMap();
	
	private String cabinId = null;
	private String returnCabinId = null;
	private CabinEntity cabinEntity = null;
	
	//请求航班的时候有连续几个请求，间隔时间不同一般的请求间隔
	private static final long susInterval = 0;
	//请求间隔
	private static final long requestInterval = 10 * 1000;
	private long interval = 0;
	
	/**
	 * 筛选请求的内容
	 * @author stub
	 *
	 */
	private enum QueryFlag{
		ALL(0,"所有票价类型"),
		NF(1,"除了头等舱的票价类型"),
		F(2,"选择头等舱所有票价"),//首页选择头等舱，然后包括各种舱位的正常价格和最低价格
		FL(3,"选择头等舱最低票价"); //首页选择头等舱 包括所有舱位最低价格的情况
		
		private int flag;
		private String desc;
		private QueryFlag(int flag,String desc){
			this.flag = flag;
			this.desc = desc;
		}
	}
	//请求筛选
	private static final QueryFlag fl =QueryFlag.ALL;
	
	//舱位
	private static final Map<String,String> cabins = new LinkedHashMap<String, String>(){
		/**
		 * 
		 */
		private static final long serialVersionUID = 1321608441260197410L;

		{
			//put("ECOSPCL1", "经济舱特价");
			put("ECONOMY1", "经济舱");
			put("PRESTIGE1", "商务舱");
			//put("", "头等舱");
		}
	};
	
	//首页选择头等舱之后的选择的舱位(票价类型)
	private static final Map<String,String> fCabins = new LinkedHashMap<String, String>(){
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		{
			put("F", "头等舱");
			put("B", "商务舱");
			put("E", "经济舱");
			put("R", "具有限制的经济舱");
		}
	};
	
	private static final Map<String,String> restriction = new LinkedHashMap<String, String>();
	
	static{
		switch (fl) {
		case ALL:
		case F:
			restriction.put("true", "最低票价");
			restriction.put("false", "正常票价");
			break;
		case FL:
			restriction.put("true", "最低票价");
			break;
		default:
			break;
		}
	}
	
	public KoreanAirAdapter_bak_1(TaskModel taskQueue) {
		super(taskQueue);
	}

	@Override
	public List<Object> paraseToVo(Object fetchObject) throws Exception {
		Map<String,AbstractPlaneInfoEntity> map = (Map<String,AbstractPlaneInfoEntity>)fetchObject;
		List<AbstractPlaneInfoEntity> list = PlaneInfoCommon.mapToList(map);
		PlaneInfoEntityBuilder.buildLimitPrice(list);
		return Arrays.asList(list.toArray());
	}

	@Override
	public String getUrl() throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object fetch(String url) throws Exception {
		logger.info("抓取开始");
		switch(fl){
			case ALL :
				int noFlight = 0;
				try{
					fetchNF();
				}catch (FlightInfoNotFoundException e) {
					noFlight ++;
				}
				try{
					fetchF();
				}catch (FlightInfoNotFoundException e) {
					noFlight ++;
				}
				if(noFlight == 2){
					throw new FlightInfoNotFoundException();
				}
				break;
			case NF:
				fetchNF();break;
			case F:
			case FL:
				fetchF();break;
			default : throw new UnsupportedOperationException();
		}
		return entityMap;
	}

	
	/**
	 * 查询经济舱和商务舱的情况
	 * @return
	 * @throws Exception
	 */
	private Object fetchNF() throws Exception{
		logger.info("抓取经济舱和商务舱-------------------");
		HttpGet g;
		HttpPost p;
		String page = null;
		Document doc;
		Map<String,String> tranParams = null;
		Map<String,String> encParams = null;
		Map<String,String> flightParams = null;
		int noFlightCount = 0;
		try {
			for(String key : cabins.keySet()){
				interval = susInterval;
				try{
					g = new HttpGet(cnHomeUrl);
					page = excute(g);
					//interval = susInterval;
					tranParams = getTranParams(tranParams);
					tranParams.put("COMMERCIAL_FARE_FAMILY_1",key);
					p = getBasePost(tranUrl,tranParams);
					p.addHeader("Host","www.koreanair.com");
					p.addHeader("Referer",cnHomeUrl);
					page = excute(p);
					
					encParams = getEncParams(encParams);
					encParams.put("COMMERCIAL_FARE_FAMILY_1",key);
					 p = getBasePost(encUrl,encParams);
					 p.addHeader("Host","www.koreanair.com");
					 p.addHeader("Referer",tranUrl);
					 page = excute(p);
					 
					 doc = Jsoup.parse(page);
					 Element enc = doc.select("input[name=enc]").first();
					 flightParams = getFlightParams(flightParams);
					 flightParams.put("COMMERCIAL_FARE_FAMILY_1",key);
					 flightParams.put("ENC",enc.val());
					p = getBasePost(flightUrl, flightParams);
					p.addHeader("Host","wftc3.e-travel.com");
					p.addHeader("Referer","http://www.koreanair.com/local/cn/ld/sch/tp/bo/sch_tp_bo_ifr.jsp");
					page = excute(p);
					try{
						validateData(page);
					}catch(FlightInfoNotFoundException e){
						noFlightCount ++;
						continue;
					}
				}catch(Exception e){
					//能抓到最低舱位的就保持数据，否则抛出异常
					if(key.equals("ECONOMY1")){
						throw e;
					}else{
						logger.info("抓取舱位:" + cabins.get(key) + "失败");
						continue;
					} 
				}
				appendPageContents(page);
				setLenghtCount(page.getBytes().length);
			    doc = Jsoup.parse(page);
			    
			    interval = requestInterval;
			    if(taskQueue.getIsReturn() == 0){
			    	parseOW(doc,cabins.get(key));
			    }else{
			    	parseRT(doc,cabins.get(key));
			    }
			}
			
			//两种舱位都无航班
			if(noFlightCount == cabins.size()){
				throw new FlightInfoNotFoundException("经济舱和商务舱都无航班或座位");
			}
		} finally {
			g = null;
			p = null;
			page = null;
			tranParams = null;
			encParams = null;
			flightParams = null;
		}
		return null;
	}
	
	/**
	 * 查询选择公务舱的情况
	 * @return
	 * @throws Exception
	 */
	private Object fetchF() throws Exception{
		logger.info("抓取选择公务舱-----------------------");
		HttpGet g;
		HttpPost p;
		String page;
		Document doc;
		Map<String,String> tranParams = null;
		Map<String,String> encParams = null;
		Map<String,String> flightParams = null;
		try {
			if(queryFPriceTime < 0){
				throw new IllegalArgumentException("fetchF must queryPrice");
			}
				
				interval = susInterval;
				g = new HttpGet(cnHomeUrl);
				page = excute(g);
				tranParams = getFTranParams(tranParams);
				p = getBasePost(tranUrl,tranParams);
				p.addHeader("Host","www.koreanair.com");
				p.addHeader("Referer",cnHomeUrl);
				page = excute(p);
				
				encParams = getFEncParams(encParams);
				 p = getBasePost(encUrl,encParams);
				 p.addHeader("Host","www.koreanair.com");
				 p.addHeader("Referer",tranUrl);
				 page = excute(p);
				 
				 doc = Jsoup.parse(page);
				 Element enc = doc.select("input[name=enc]").first();
				 flightParams = getFFlightParams(flightParams);
				 flightParams.put("ENC",enc.val());
				p = getBasePost(flightUrl, flightParams);
				p.addHeader("Host","wftc3.e-travel.com");
				p.addHeader("Referer","http://www.koreanair.com/local/cn/ld/sch/tp/bo/sch_tp_bo_ifr.jsp");
				page = excute(p);
				validateData(page);
			    doc = Jsoup.parse(page);
			    appendPageContents(page);
			    setLenghtCount(page.getBytes().length);
			    
			    interval = requestInterval;
			    if(taskQueue.getIsReturn() == 0){
			    	parseFOW(doc);
			    }else{
			    	parseFRT(doc);
			    }
		} finally {
			g = null;
			p = null;
			page = null;
			tranParams = null;
			encParams = null;
			flightParams = null;
		}
		return null;
	}
	
	private void parseRT(Document doc,String cabinType) throws Exception{
		HttpPost p;
		String page;
	    String s = RegHtmlUtil.regStr(doc.toString(), "var generatedJSon.*?\\('(.*?)'\\)");
	    JSONObject generatedJSon = JSONObject.fromObject(s);
	    JSONObject _listRecos = generatedJSon.getJSONObject("listRecos");
	   // int maxIDOutbound = generatedJSon.getInt("maxIDOutbound");
	    int maxIDInbound = generatedJSon.getInt("maxIDInbound");
	    //String recommendationIDs = generatedJSon.getString("recosIDs");
	    
	    Element fdff_form = doc.getElementById("FDFF_FORM");
    	String url = fdff_form.attr("action");
    	Map<String,String> params = PlaneInfoCommon.getNameParams(fdff_form);
    	params.remove("FDFF_FORM");
    	params.put("selectSortFlights_out", "E");//排序方法 飞行时间
    	params.put("IS_DIRTY_OUTBOUND", "Y");
    	params.put("IS_DIRTY_INBOUND", "Y");
    	
	    Elements priceInputs = doc.select("td[id^=FRB_] input[type=radio]");
	    for(Element priceInput : priceInputs){
	    	String price = priceInput.parent().text();
	    	String cabinName = priceInput.parent().siblingElements().get(1).text();
	    	String onclick = priceInput.attr("onclick");
	    	String selectedRecommendationID  = RegHtmlUtil.regStr(onclick,"selectRecommendationSet\\('(.*?)',");
	    	
	    	Object associatedRecosObj = _listRecos.getJSONObject(selectedRecommendationID).get("associatedRecos");
	    	JSONArray associatedRecos = null;
	    	if(associatedRecosObj != null){
			    associatedRecos = (JSONArray)associatedRecosObj;
			 }
	    	String outFlightsList = _listRecos.getJSONObject(selectedRecommendationID).getString("outboundFlightIDs");
	    	String inFlightsList = _listRecos.getJSONObject(selectedRecommendationID).getString("inboundFlightIDs");
	    	if(outFlightsList == null || outFlightsList.equals("")){
	    		logger.info("无去程航班");
	    		continue;
	    	}
	    	if(inFlightsList == null || inFlightsList.equals("")){
	    		logger.info("无回程航班");
	    		continue;
	    	}
	    	
	    	String[] outFlightIDs = outFlightsList.replaceAll("^\\||\\|$", "").split("\\|");
	    	//选择去程前面之后还会有筛选
	    	//String[]  inFlightIDs = inFlightsList.replaceAll("^\\||\\|$", "").split("\\|");
	    
	    	for(String outId : outFlightIDs){
	    		//Element outFlightInput = doc.getElementById("R_0_" + outId);
	    		List<String> inFlightIDs = new ArrayList<String>();
	    		boolean flightIdFound = false;
	    		for(int i = 0; i < maxIDInbound;i++){
	    			if(associatedRecos != null){
			    		for(Object lTrueID : associatedRecos){
			    			int lTrueIDInt = (Integer)lTrueID;
			    			String lTrueIDStr = String.valueOf(lTrueIDInt);
			    			JSONArray  inboundFlights = _listRecos.getJSONObject(lTrueIDStr).getJSONArray("inboundFlights");
			    			if(inboundFlights.size() > Integer.valueOf(outId)){
				    			Object inboundFlight = inboundFlights.get(Integer.valueOf(outId));
				    			if(inboundFlight != null){
				    				if(inboundFlight.toString().indexOf("|" + i +  "|") >= 0){
				    					flightIdFound = true;
				    					break;
				    				}
				    			}
			    			}
			    		}
			    	}
			    	if(flightIdFound){
			    		inFlightIDs.add(String.valueOf(i));
			    	}else{
			    		JSONArray inboundFlights =  _listRecos.getJSONObject(selectedRecommendationID).getJSONArray("inboundFlights");
			    		if(inboundFlights.size() > Integer.valueOf(outId)){
				    		Object inboundFlight = inboundFlights.get(Integer.valueOf(outId));
				    		if(inboundFlight != null && inboundFlight.toString().indexOf("|" + i +  "|") >= 0){
				    			inFlightIDs.add(String.valueOf(i));
				    		}
			    		}
			    	}
	    		}
	    		
	    		for(String inId : inFlightIDs){
	    			//Element inFlightInput = doc.getElementById("R_1_" + inId);
		    		String iRecommendationID = selectedRecommendationID;
			    	if(associatedRecos != null){
			    		for(Object lTrueID : associatedRecos){
			    			int lTrueIDInt = (Integer)lTrueID;
			    			String lTrueIDStr = String.valueOf(lTrueIDInt);
			    			if(_listRecos.getJSONObject(lTrueIDStr).getString("outboundFlightIDs").indexOf("|" + outId + "|") >= 0){
			    				if(maxIDInbound > 0){
			    					if(_listRecos.getJSONObject(lTrueIDStr).getString("inboundFlightIDs").indexOf("|" + inId + "|") >= 0){
			    						iRecommendationID = lTrueIDStr;
			    					}
			    				}else{
			    					iRecommendationID = lTrueIDStr;
			    				}
			    			}
			    		}
			    	}
		    		params.put("FLIGHTOUTBOUND", outId);
		    		params.put("FLIGHTINBOUND", inId);
		    		params.put("FamilyButton", priceInput.val());
		    		params.put("RECOMMENDATION_ID_1", iRecommendationID);
		    		params.put("FLIGHT_ID_1", outId);
		    		params.put("FLIGHT_ID_2", inId);
		    		
		    		
		    		List<FlightInfo> goFlightInfos = buildFlightInfos(doc.getElementById("FT_0_" + outId));
		    		List<FlightInfo> returnFlightInfos = buildFlightInfos(doc.getElementById("FT_1_" + inId));;
		    		p = getBasePost(url, params);
		    		//如果航班页不是提示无航班，而是其他的异常，则拿第二层的数据，否则拿page层的数据
		    		Document taxDoc = null;
		    		if(queryPriceTime > 0){
			    		try{
							for(int i = 0;i < queryPriceTime;i++){
								try{
									page = excute(p, 1, swapIpRegex);
					    			validateData(page);
					    			appendPageContents(page);
									setLenghtCount(page.getBytes().length);
									taxDoc = Jsoup.parse(page);
									Element goTable = taxDoc.getElementById("tabFgtReview_0");
									Element returnTable = taxDoc.getElementById("tabFgtReview_1");
									fillFlightInfos(goTable, goFlightInfos);
									fillFlightInfos(returnTable, returnFlightInfos);
									break;
								}catch(FlightInfoNotFoundException fe){
									throw fe;
								}catch(Exception e){
									logger.info("第" + (i + 1) + "次构建税费失败");
									logger.error(e);
								}
							}
			    		}catch(FlightInfoNotFoundException e){
			    			continue;
			    		}
		    		}
		    		parseDetialRT(taxDoc,goFlightInfos,returnFlightInfos,cabinType ,cabinName,cabinType + cabinName + price,price);
		    	}
	    	}
	    }
	}
	
	/**
	 * 抓取经济舱和商务舱单程
	 * @param doc
	 * @param cabinType
	 * @throws Exception
	 */
	private void parseOW(Document doc,String cabinType) throws Exception{
		HttpPost p;
		String page;
	    String s = RegHtmlUtil.regStr(doc.toString(), "var generatedJSon.*?\\('(.*?)'\\)");
	    JSONObject generatedJSon = JSONObject.fromObject(s);
	    JSONObject _listRecos = generatedJSon.getJSONObject("listRecos");
	   // int maxIDOutbound = generatedJSon.getInt("maxIDOutbound");
	    int maxIDInbound = generatedJSon.getInt("maxIDInbound");
	    //String recommendationIDs = generatedJSon.getString("recosIDs");
	    
	    Element fdff_form = doc.getElementById("FDFF_FORM");
    	String url = fdff_form.attr("action");
    	Map<String,String> params = PlaneInfoCommon.getNameParams(fdff_form);
    	params.remove("FDFF_FORM");
    	params.put("selectSortFlights_out", "E");//排序方法 飞行时间
    	params.put("IS_DIRTY_OUTBOUND", "Y");
    	
	    Elements priceInputs = doc.select("td[id^=FRB_] input[type=radio]");
	    for(Element priceInput : priceInputs){
	    	String price = priceInput.parent().text();
	    	String cabinName = priceInput.parent().siblingElements().get(1).text();
	    	String onclick = priceInput.attr("onclick");
	    	String selectedRecommendationID  = RegHtmlUtil.regStr(onclick,"selectRecommendationSet\\('(.*?)',");
	    	
	    	Object associatedRecosObj = _listRecos.getJSONObject(selectedRecommendationID).get("associatedRecos");
	    	JSONArray associatedRecos = null;
	    	if(associatedRecosObj != null){
			    associatedRecos = (JSONArray)associatedRecosObj;
			 }
	    	String outFlightsList = _listRecos.getJSONObject(selectedRecommendationID).getString("outboundFlightIDs");
	    	if(outFlightsList == null || outFlightsList.equals("")){
	    		logger.info("无去程航班");
	    		continue;
	    	}
	    	String[] outFlightIDs = outFlightsList.replaceAll("^\\||\\|$", "").split("\\|");
	    	//选择去程前面之后还会有筛选
	    	//String[]  inFlightIDs = inFlightsList.replaceAll("^\\||\\|$", "").split("\\|");
	    
	    	for(String outId : outFlightIDs){
	    		//Element outFlightInput = doc.getElementById("R_0_" + outId);
	    			
	    			//Element inFlightInput = doc.getElementById("R_1_" + inId);
		    		String iRecommendationID = selectedRecommendationID;
		    		if(associatedRecos != null){
			    		for(Object lTrueID : associatedRecos){
			    			int lTrueIDInt = (Integer)lTrueID;
			    			String lTrueIDStr = String.valueOf(lTrueIDInt);
			    			if(_listRecos.getJSONObject(lTrueIDStr).getString("outboundFlightIDs").indexOf("|" + outId + "|") >= 0){
			    					iRecommendationID = lTrueIDStr;
			    		}
			    		}
			    	}
		    		params.put("FLIGHTOUTBOUND", outId);
		    		params.put("FamilyButton", priceInput.val());
		    		params.put("RECOMMENDATION_ID_1", iRecommendationID);
		    		params.put("FLIGHT_ID_1", outId);
		    		
		    		
		    		List<FlightInfo> goFlightInfos = buildFlightInfos(doc.getElementById("FT_0_" + outId));
		    		p = getBasePost(url, params);
		    		//如果航班页不是提示无航班，而是其他的异常，则拿第二层的数据，否则拿page层的数据
		    		Document taxDoc = null;
		    		if(queryPriceTime > 0){
			    		try{
							for(int i = 0;i < queryPriceTime;i++){
								try{
									page = excute(p, 1, swapIpRegex);
					    			validateData(page);
					    			appendPageContents(page);
									setLenghtCount(page.getBytes().length);
									taxDoc = Jsoup.parse(page);
									Element goTable = taxDoc.getElementById("tabFgtReview_0");
									fillFlightInfos(goTable, goFlightInfos);
									break;
								}catch(FlightInfoNotFoundException fe){
									throw fe;
								}catch(Exception e){
									logger.info("第" + (i + 1) + "次构建税费失败");
									logger.error(e);
								}
							}
			    		}catch(FlightInfoNotFoundException e){
			    			continue;
			    		}
		    		}
		    		parseDetialOW(taxDoc,goFlightInfos,cabinType ,cabinName,price);
	    	}
	    }
	}
	
	/**
	 *构建往返
	 * @param page
	 * @throws Exception
	 */
	private void parseDetialRT(Document doc,List<FlightInfo> goFlightInfos,List<FlightInfo> returnFlightInfos,String cabinType,String cabinName,String cabinKey,String price) throws Exception{
		DoublePlaneInfoEntity entity;
		entity = buildEntity(DoublePlaneInfoEntity.class, goFlightInfos, null, cabinType, cabinName,cabinKey);
		buildEntity(ReturnDoublePlaneInfoEntity.class, returnFlightInfos, entity, cabinType, cabinName,cabinKey);
		CabinRelationEntity relation = new CabinRelationEntity();
		relation.setCabinId(cabinId);
		relation.setReturnCabinId(returnCabinId);
		try{
			Double taxesPrice = PlaneInfoEntityBuilder.getDouble(doc.getElementById("taxes_ADT").text());
			Double totalPrice =  PlaneInfoEntityBuilder.getDouble(doc.getElementById("spanTotalPriceOfAllPax").text());
			relation.setFullPrice(totalPrice - taxesPrice);
			relation.setTaxesPrice(taxesPrice);
			relation.setTotalFullPrice(totalPrice);
		}catch(Exception e){
			logger.error("查询税价失败", e);
			if(price == null){
				throw new IllegalArgumentException("price is null");
			}
			relation.setTotalFullPrice(PlaneInfoEntityBuilder.getDouble(price));
		}
		entity.getCabinRelations().add(relation);
	}
	
	/**
	 *构建单程
	 * @param doc
	 * @param goFlightInfos
	 * @param cabinType
	 * @param cabinName
	 * @param price
	 * @throws Exception
	 */
	private void parseDetialOW(Document doc,List<FlightInfo> goFlightInfos,String cabinType,String cabinName,String price) throws Exception{
		buildEntity(SinglePlaneInfoEntity.class, goFlightInfos, null, cabinType, cabinName,cabinType + cabinName);
		try{
			Double taxesPrice = PlaneInfoEntityBuilder.getDouble(doc.getElementById("taxes_ADT").text());
			Double totalPrice =  PlaneInfoEntityBuilder.getDouble(doc.getElementById("spanTotalPriceOfAllPax").text());
			cabinEntity.setPrice(totalPrice - taxesPrice);
			cabinEntity.setTaxesPrice(taxesPrice);
			cabinEntity.setOriginalPrice(totalPrice);
		}catch(Exception e){
			if(price == null){
				throw new IllegalArgumentException("price is null");
			}
			cabinEntity.setPrice(PlaneInfoEntityBuilder.getDouble(price));
		}
	}
	
	/**
	 * 选择头等舱的往返
	 * @param doc
	 * @throws Exception 
	 */
	private void parseFRT(Document doc) throws Exception{
		HttpPost p;
		String page;
		Document taxDoc = null;
		
		 Element form = doc.getElementById("form");
	     String url = form.attr("action");
	     url = url.startsWith("http")? url : "https://wftc3.e-travel.com" + url;
	     Map<String,String> params = PlaneInfoCommon.getNameParams(form);
	     params.remove("SDAIForm");
	     Elements outRadios = doc.select("input[type=radio][id^=rdo_0]");
	     Elements inRadios = doc.select("input[type=radio][id^=rdo_1]");
	     for(Element out : outRadios){
	    	 params.put("ROW_1", out.val());
	    	 List<FlightInfo> goFlightInfos = buildFlightInfos(out.parent().siblingElements().get(0));
	    	 for(Element in : inRadios){
	    		 params.put("ROW_2", in.val());
	    		 List<FlightInfo> returnFlightInfos = buildFlightInfos(in.parent().siblingElements().get(0));
	    		 for(String cabin : fCabins.keySet()){
	    			 params.put("CABIN", cabin);
	    			 for(String ticketType : restriction.keySet()){
	    				 params.put("RESTRICTION", ticketType);
	    				 try{
		    				 for(int i = 0; i < queryFPriceTime;i++){
		    					 try{
				    				 p = getBasePost(url, params);
				    				 page = excute(p, 1, swapIpRegex);
				    				 validateData(page);
				    				 appendPageContents(page);
				    				 setLenghtCount(page.getBytes().length);
				    				 taxDoc = Jsoup.parse(page);
				    				 Element goTable = taxDoc.getElementById("tabFgtReview_0");
									Element returnTable = taxDoc.getElementById("tabFgtReview_1");
									fillFlightInfos(goTable, goFlightInfos);
									fillFlightInfos(returnTable, returnFlightInfos);
									break;
		    					 }catch(FlightInfoNotFoundException e){
		    						 throw e;
		    					 }catch (Exception e) {
		    						 if(i == queryFPriceTime - 1){
		    							 throw e;
		    						 }
								}
		    				 }
	    				 }catch(FlightInfoNotFoundException e){
	    					 continue;
	    				 }
	    				 parseDetialRT(taxDoc, goFlightInfos, returnFlightInfos, "头等舱",fCabins.get(cabin) + restriction.get(ticketType) , fCabins.get(cabin) + restriction.get(ticketType),null);
	    			 }
	    		 }
	    	 }
	     }
	     
	}
	
	/**
	 * 选择头等舱的单程
	 * @param doc
	 * @throws Exception 
	 */
	private void parseFOW(Document doc) throws Exception{
		HttpPost p;
		String page;
		Document taxDoc = null;
		
		 Element form = doc.getElementById("form");
	     String url = form.attr("action");
	     url = url.startsWith("http")? url : "https://wftc3.e-travel.com" + url;
	     Map<String,String> params = PlaneInfoCommon.getNameParams(form);
	     params.remove("SDAIForm");
	     Elements outRadios = doc.select("input[type=radio][id^=rdo_0]");
	     for(Element out : outRadios){
	    	 params.put("ROW_1", out.val());
	    	 List<FlightInfo> goFlightInfos = buildFlightInfos(out.parent().siblingElements().get(0));
	    		 for(String cabin : fCabins.keySet()){
	    			 params.put("CABIN", cabin);
	    			 for(String ticketType : restriction.keySet()){
	    				 params.put("RESTRICTION", ticketType);
	    				 try{
		    				 for(int i = 0; i < queryFPriceTime;i++){
		    					 try{
				    				 p = getBasePost(url, params);
				    				 page = excute(p, 1, swapIpRegex);
				    				 validateData(page);
				    				 appendPageContents(page);
				    				 setLenghtCount(page.getBytes().length);
				    				 taxDoc = Jsoup.parse(page);
				    				 Element goTable = taxDoc.getElementById("tabFgtReview_0");
									fillFlightInfos(goTable, goFlightInfos);
									break;
		    					 }catch(FlightInfoNotFoundException e){
		    						 throw e;
		    					 }catch (Exception e) {
		    						 if(i == queryFPriceTime - 1){
		    							 logger.error("抓取头等舱类型价格失败");
		    							 throw e;
		    						 }
								}
		    				 }
	    				 }catch(FlightInfoNotFoundException e){
	    					 continue;
	    				 }
	    				 parseDetialOW(taxDoc, goFlightInfos,  "头等舱",fCabins.get(cabin) + restriction.get(ticketType) , null);
	    			 }
	    		 }
	     }
	     
	}
	
	/**
	 * 
	 * @param table  每一段航班，去程或回程
	 * @return
	 * @throws ParseException 
	 */
	private List<FlightInfo> buildFlightInfos(Element table) throws ParseException{
		Elements spans = table.select("span.nameHighlight");
		Elements flightNoSpans = new Elements();
		for(Element span : spans){
			if(span.children().size() < 1){
				flightNoSpans.add(span);
			}
		}
		List<FlightInfo> list = new ArrayList<FlightInfo>();
		for(int i = 0; i < flightNoSpans.size(); i++){
			FlightInfo info = new FlightInfo();
			info.setFlightNo(RegHtmlUtil.regStr(flightNoSpans.get(i).text(), "\\((.*?)\\)"));
			if(i == 0){
				info.setFromAirport(taskQueue.getFromCity());
				Element beginTimeElement = table.getElementsMatchingOwnText("\\d+:\\d+").first();
				Elements beginCountElement = beginTimeElement.siblingElements().select("span.textSmaller");
				int beginCount = 0;
				if(!beginCountElement.isEmpty()){
					beginCount = Integer.valueOf(RegHtmlUtil.regStr(beginCountElement.text(),"\\+(\\d{1}).*?天"));
				}
				info.setStartTime(DateUtil.addDate(PlaneInfoCommon.getFormatTime(taskQueue.getFlightDate(),beginTimeElement.text().trim()),beginCount));				
				info.setFlightDuration(PlaneInfoCommon.getStayTime(table.getElementsMatchingOwnText("(\\d+小时)|(\\d+分)").first().text()));
			}
			if(i == flightNoSpans.size() - 1){
				info.setToAirport(taskQueue.getToCity());
				Element endTimeElement = table.getElementsMatchingOwnText("\\d+:\\d+").get(1);
				Elements endCountElement = endTimeElement.siblingElements().select("span.textSmaller");
				int endCount = 0;
				if(!endCountElement.isEmpty()){
					endCount = Integer.valueOf(RegHtmlUtil.regStr(endCountElement.text(),"\\+(\\d{1}).*?天"));
				}
				info.setEndTime(DateUtil.addDate(PlaneInfoCommon.getFormatTime(taskQueue.getFlightDate(),endTimeElement.text().trim()),endCount));					
			}
			list.add(info);
		}
		return list;
	}
	
	/**
	 * 构建FlightInfo，税费页面
	 * @param table 去程或回程的所有航班
	 * @return
	 * @throws ParseException 
	 */
	private void  fillFlightInfos(Element table,List<FlightInfo> flightInfos) throws ParseException,Exception{
		Pattern datePattren = Pattern.compile("\\d+年\\d+月\\d+日星期");
		Pattern timePattern = Pattern.compile("\\d{1,2}:\\d{1,2}");
		for(int i = 0;i < flightInfos.size();i++){
			FlightInfo info = flightInfos.get(i);
			info.setFlightType(table.select("[id^=segAircraft_]").get(i).text().trim());
			String date = table.getElementsMatchingOwnText(datePattren).get(i).text();
			Element beginTimeElement = table.getElementsMatchingOwnText(timePattern).get((i + 1) * 2 - 2);
			String beginTime = beginTimeElement.text();
			int beginCount = 0;
			Elements beginCountElement = beginTimeElement.select("span.textSmaller");
			if(!beginCountElement.isEmpty()){
				beginCount = Integer.valueOf(RegHtmlUtil.regStr(beginCountElement.text(),"\\+(\\d{1}.*?天"));
			}
			Element endTimeElement = table.getElementsMatchingOwnText(timePattern).get((i + 1) * 2 - 1);
			String endTime = endTimeElement.text();
			int endCount = 0;
			Elements endCountElement = endTimeElement.select("span.textSmaller");
			if(!endCountElement.isEmpty()){
				endCount = Integer.valueOf(RegHtmlUtil.regStr(endCountElement.text(),"\\+(\\d{1}).*?天"));
			}
			info.setStartTime(DateUtil.addDate(PlaneInfoCommon.getFormatTime(date, beginTime),beginCount));
			info.setEndTime(DateUtil.addDate(PlaneInfoCommon.getFormatTime(date, endTime),endCount));
			if(i != flightInfos.size() -1){
				info.setStopTime(PlaneInfoCommon.getStayTime(table.select("div.textChangeAirport.textChangeAirportTextBold").get(i).text()));
			}
			info.setFromAirportName(beginTimeElement.siblingElements().get(1).text().trim());
			info.setToAirportName(endTimeElement.siblingElements().get(1).text().trim());
		}
	}
	
	/**
	 * 构建实体，如果是往返回程，去程实体不能为空
	 * @param clazz
	 * @param flightInfos
	 * @param dEntity
	 * @param cabinType
	 * @param cabinName
	 * @return
	 * @throws Exception
	 */
	private <T extends AbstractPlaneInfoEntity> T  buildEntity(Class<T> clazz,List<FlightInfo> flightInfos,DoublePlaneInfoEntity dEntity,
			String cabinType,String cabinName,String cabinKey) throws Exception{
		AbstractPlaneInfoEntity entity = null;
		String flightNos = "";
		for(FlightInfo flightInfo : flightInfos){
			flightNos += flightInfo.getFlightNo();
		}
		if(clazz.equals(SinglePlaneInfoEntity.class) || clazz.equals(DoublePlaneInfoEntity.class)){
			if(!entityMap.containsKey(flightNos)){
				FlightInfo firstInfo = flightInfos.get(0);
				FlightInfo lastInfo = flightInfos.get(flightInfos.size() - 1);
				entity = PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, carrierKey, carrierName, carrierFullName, firstInfo.getStartTime(), lastInfo.getEndTime(),firstInfo.getFlightNo() , null,
						null, null, firstInfo.getFlightType());
				if(clazz.equals(SinglePlaneInfoEntity.class)){
					((SinglePlaneInfoEntity)entity).setFlightDuration(firstInfo.getFlightDuration());
				}else{
					((DoublePlaneInfoEntity)entity).setFlightDuration(firstInfo.getFlightDuration());
				}
				
				if(flightInfos.size() > 1){
					for(FlightInfo info : flightInfos){
						TransitEntity tran = PlaneInfoEntityBuilder.buildTransitEntity(info.getFlightNo(), info.getFlightNo(), carrierKey, carrierName, carrierFullName, 
								info.getFromAirport(), info.getFromAirportName(), info.getToAirport(), info.getToAirportName(), info.getFlightType(), TransitEntity.class);
						if(info.getStartTime() != null){
							tran.setStartTime(format.parse(info.getStartTime()));
						}
						if(info.getEndTime() != null){
							tran.setEndTime(format.parse(info.getEndTime()));
						}
						tran.setStayTime(info.getStopTime());
						if(clazz.equals(SinglePlaneInfoEntity.class)){
							((SinglePlaneInfoEntity)entity).getTransits().add(tran);
						}else{
							((DoublePlaneInfoEntity)entity).getTransits().add(tran);
						}
					}
				}
				entityMap.put(flightNos, entity);
			}else{
				entity = entityMap.get(flightNos);
			}
			
			if(clazz.equals(DoublePlaneInfoEntity.class)){
				if(cabinMap.containsKey(flightNos)){
					List<String> cabinList = cabinMap.get(flightNos);
					if(cabinList.contains(cabinKey)){
						cabinId = cabinIdMap.get(cabinKey);
						return (T)entity;
					}else{
						cabinList.add(cabinKey);
					}
				}else{
					List<String> list = Lists.newArrayList();
					list.add(cabinKey);
					cabinMap.put(flightNos, list);
				}
			}
			CabinEntity cabin = PlaneInfoEntityBuilder.buildCabinInfo(cabinType, null, cabinName, null, null, null, null, null,CabinEntity.class);
			cabinEntity = cabin;
			cabinId = cabin.getId();
			if(clazz.equals(SinglePlaneInfoEntity.class)){
				((SinglePlaneInfoEntity)entity).getCabins().add(cabin);
			}else{
				((DoublePlaneInfoEntity)entity).getCabins().add(cabin);
				cabinIdMap.put(cabinKey, cabinId);
			}
		}else{
			if(dEntity == null){
				throw new IllegalArgumentException("DoublePlaneInfoEntity is null");
			}
			entity = PlaneInfoCommon.getExistReturnEntity(dEntity, flightNos);
			if(entity == null){
				FlightInfo firstInfo = flightInfos.get(0);
				FlightInfo lastInfo = flightInfos.get(flightInfos.size() - 1);
				entity = PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, carrierKey, carrierName, carrierFullName, firstInfo.getStartTime(), lastInfo.getEndTime(),firstInfo.getFlightNo() , null,
						null, null, firstInfo.getFlightType(),ReturnDoublePlaneInfoEntity.class);
				
				if(clazz.equals(SinglePlaneInfoEntity.class)){
					((SinglePlaneInfoEntity)entity).setFlightDuration(firstInfo.getFlightDuration());
				}else{
					((ReturnDoublePlaneInfoEntity)entity).setFlightDuration(firstInfo.getFlightDuration());
				}
				
				if(flightInfos.size() > 1){
					for(FlightInfo info : flightInfos){
						ReturnTransitEntity tran = PlaneInfoEntityBuilder.buildTransitEntity(info.getFlightNo(), info.getFlightNo(), carrierKey, carrierName, carrierFullName, 
								info.getFromAirport(), info.getFromAirportName(), info.getToAirportName(), null, info.getFlightType(), ReturnTransitEntity.class);
						if(info.getStartTime() != null){
							tran.setStartTime(format.parse(info.getStartTime()));
						}
						if(info.getEndTime() != null){
							tran.setEndTime(format.parse(info.getEndTime()));
						}
						tran.setStayTime(info.getStopTime());
						((ReturnDoublePlaneInfoEntity)entity).getReturnTransits().add((ReturnTransitEntity)tran);
					}
				}
				dEntity.getReturnPlaneInfos().add((ReturnDoublePlaneInfoEntity)entity);
			}
			ReturnCabinEntity returnCabin = PlaneInfoEntityBuilder.buildCabinInfo(cabinType, null, cabinName, null, 
					null, null, null, null,ReturnCabinEntity.class);
			returnCabinId = returnCabin.getId();
			((ReturnDoublePlaneInfoEntity)entity).getReturnCabins().add(returnCabin);
		}
		return (T)entity;
	}
	
	/**
	 * 获取请求航班的参数
	 * @param params
	 * @return
	 */
	private Map<String,String> getFlightParams(Map<String,String> params){
		if(params == null){
			params = Maps.newHashMap();
		}
		if(!params.isEmpty()){
			return params;
		}
		//params.put("COMMERCIAL_FARE_FAMILY_1",cabinType);
		//params.put("ENC",enc);
		params.put("ARRANGE_BY","E");
		params.put("B_ANY_TIME_1","TRUE");
		params.put("B_ANY_TIME_2","TRUE");
		params.put("CABIN","");
		params.put("DATE_RANGE_QUALIFIER_1","C");
		params.put("DATE_RANGE_QUALIFIER_2","C");
		params.put("DATE_RANGE_VALUE_1","0");
		params.put("DATE_RANGE_VALUE_2","0");
		params.put("DIRECT_LOGIN","NO");
		params.put("DISPLAY_TYPE","2");
		params.put("EMBEDDED_TRANSACTION","FlexPricerAvailability");
		params.put("ENCT","1");
		params.put("EXTERNAL_ID","QEC");
		params.put("FIELD_ADT_NUMBER","1");
		params.put("FIELD_CHD_NUMBER","0");
		params.put("FIELD_INFANTS_NUMBER","0");
		params.put("HAS_INFANT_1","");
		params.put("HAS_INFANT_2","");
		params.put("HAS_INFANT_3","");
		params.put("HAS_INFANT_4","");
		params.put("HAS_INFANT_5","");
		params.put("HAS_INFANT_6","");
		params.put("HAS_INFANT_7","");
		params.put("HAS_INFANT_8","");
		params.put("HAS_INFANT_9","");
		params.put("H_Site","CN");
		params.put("LANGUAGE","CN");
		params.put("PRICING_TYPE","I");
		params.put("SEARCH_PAGE","SD");
		params.put("SESSION_ID","");
		params.put("SEVEN_DAY_SEARCH","TRUE");
		params.put("SITE","CAUOCAUO");
		params.put("SO_GL","");
		params.put("SO_LANG_SITE_AGENCY_LINE1","Korean Air China Service Center(Qingdao)");
		params.put("SO_LANG_SITE_AGENCY_LINE2","TEL) 86-40065-88888");
		params.put("SO_LANG_SITE_AGENCY_LINE3","");
		params.put("SO_LANG_SITE_AGENCY_LINE4","");
		params.put("SO_LANG_SITE_EMAIL_ADDRESS","chinaservicecenter@koreanair.com");
		params.put("SO_QUEUE_OFFICE_ID","SELKE1200");
		params.put("SO_SITE_CLASS_OF_SERVICE","in availability page");
		params.put("SO_SITE_EXT_PSPURL","https://cyb.koreanair.com/iKalApp/cn/int/purchase/chn_paymentProcess.jsp");
		params.put("SO_SITE_FORCE_DDAY_AVAIL","TRUE");
		params.put("SO_SITE_FP_BACKUP_TO_CAL","TRUE");
		params.put("SO_SITE_MAIL_FROM","chinaservicecenter@koreanair.com");
		params.put("SO_SITE_MAIL_REPLY_TO","chinaservicecenter@koreanair.com");
		params.put("SO_SITE_MOD_DELIVERY","FALSE");
		params.put("TRAVELLER_TYPE_1","ADT");
		params.put("TRAVELLER_TYPE_2","");
		params.put("TRAVELLER_TYPE_3","");
		params.put("TRAVELLER_TYPE_4","");
		params.put("TRAVELLER_TYPE_5","");
		params.put("TRAVELLER_TYPE_6","");
		params.put("TRAVELLER_TYPE_7","");
		params.put("TRAVELLER_TYPE_8","");
		params.put("TRAVELLER_TYPE_9","");
		params.put("TRIP_TYPE",getTripType());
		params.put("actionURL","http://www.koreanair.com/local/cn/ld/sch/tp/bo/sch_tp_bo_ifr.jsp");
		params.put("agentCode","QEC");
		params.put("gweb_kal","rkddnjstlr");
		return params;
	}
	
	private Map<String,String> getFFlightParams(Map<String,String> params){
		if(params == null){
			params = Maps.newHashMap();
		}
		if(!params.isEmpty()){
			return params;
		}
		//params.put("ENC",enc);
		params.put("ARRANGE_BY","E");
		params.put("B_ANY_TIME_1","TRUE");
		params.put("B_ANY_TIME_2","TRUE");
		params.put("CABIN","");
		params.put("DIRECT_LOGIN","NO");
		params.put("EMBEDDED_TRANSACTION","AirAvailability");
		params.put("ENCT","1");
		params.put("EXTERNAL_ID","QEC");
		params.put("FIELD_ADT_NUMBER","1");
		params.put("FIELD_CHD_NUMBER","0");
		params.put("FIELD_INFANTS_NUMBER","0");
		params.put("HAS_INFANT_1","");
		params.put("HAS_INFANT_2","");
		params.put("HAS_INFANT_3","");
		params.put("HAS_INFANT_4","");
		params.put("HAS_INFANT_5","");
		params.put("HAS_INFANT_6","");
		params.put("HAS_INFANT_7","");
		params.put("HAS_INFANT_8","");
		params.put("HAS_INFANT_9","");
		params.put("H_Site","CN");
		params.put("LANGUAGE","CN");
		params.put("SEARCH_PAGE","SD");
		params.put("SESSION_ID","");
		params.put("SEVEN_DAY_SEARCH","TRUE");
		params.put("SITE","CAUOCAUO");
		params.put("SO_GL","");
		params.put("SO_LANG_SITE_AGENCY_LINE1","Korean Air China Service Center(Qingdao)");
		params.put("SO_LANG_SITE_AGENCY_LINE2","TEL) 86-40065-88888");
		params.put("SO_LANG_SITE_AGENCY_LINE3","");
		params.put("SO_LANG_SITE_AGENCY_LINE4","");
		params.put("SO_LANG_SITE_EMAIL_ADDRESS","chinaservicecenter@koreanair.com");
		params.put("SO_QUEUE_OFFICE_ID","SELKE1200");
		params.put("SO_SITE_CLASS_OF_SERVICE","in availability page");
		params.put("SO_SITE_EXT_PSPURL","https://cyb.koreanair.com/iKalApp/cn/int/purchase/chn_paymentProcess.jsp");
		params.put("SO_SITE_FP_BACKUP_TO_CAL","TRUE");
		params.put("SO_SITE_MAIL_FROM","chinaservicecenter@koreanair.com");
		params.put("SO_SITE_MAIL_REPLY_TO","chinaservicecenter@koreanair.com");
		params.put("SO_SITE_MOD_DELIVERY","FALSE");
		params.put("TRAVELLER_TYPE_1","ADT");
		params.put("TRAVELLER_TYPE_2","");
		params.put("TRAVELLER_TYPE_3","");
		params.put("TRAVELLER_TYPE_4","");
		params.put("TRAVELLER_TYPE_5","");
		params.put("TRAVELLER_TYPE_6","");
		params.put("TRAVELLER_TYPE_7","");
		params.put("TRAVELLER_TYPE_8","");
		params.put("TRAVELLER_TYPE_9","");
		params.put("TRIP_TYPE",getTripType());
		params.put("actionURL","http://www.koreanair.com/local/cn/ld/sch/tp/bo/sch_tp_bo_ifr.jsp");
		params.put("agentCode","QEC");
		params.put("gweb_kal","rkddnjstlr");
		return params;
	}
	
	private Map<String,String> getTranParams(Map<String,String> params){
		if(params == null){
			params = Maps.newHashMap();
		}
		if(!params.isEmpty()){
			return params;
		}
		String[] goDate = taskQueue.getFlightDate().split("-");
		String[] returnDate = taskQueue.getReturnGrabDate().split("-");
		params.put("AIRLINE_1_1","KE");
		params.put("ARRANGE_BY","N");
		params.put("B_ANY_TIME_1","TRUE");
		params.put("B_ANY_TIME_2","TRUE");
		params.put("B_DATE_1",getRequestDate(taskQueue.getFlightDate()));
		params.put("B_DATE_2",getRequestDate(taskQueue.getReturnGrabDate()));
		params.put("B_DAY",goDate[2]);
		params.put("B_LOCATION_1",taskQueue.getFromCity());
		params.put("B_MONTH",goDate[0] + goDate[1]);
		//params.put("B_REG_ID","CHN");出发国家
		params.put("B_TIME","0000");
		params.put("CABIN","");
		//params.put("COMMERCIAL_FARE_FAMILY_1",cabinType);
		params.put("DATE_RANGE_VALUE_1","0");
		params.put("DIRECT_LOGIN","NO");
		params.put("EXTERNAL_ID","KE");
		params.put("E_DAY",returnDate[2]);
		params.put("E_LOCATION_1",taskQueue.getToCity());
		params.put("E_MONTH",returnDate[0] + returnDate[1]);
		//params.put("E_REG_ID","EUR");到达国家
		params.put("E_TIME","0000");
		params.put("H_Site","CN");
		params.put("LANGUAGE","CN");
		params.put("SERVLET_NAME_KEY","FlexPricerAvailability");
		params.put("SESSION_ID","");
		params.put("SEVEN_DAY_SEARCH","TRUE");
		params.put("SITE","CAUOCAUO");
		params.put("SO_SITE_FP_BACKUP_TO_CAL","TRUE");
		params.put("TRAVELLER_TYPE","1");
		params.put("TRAVELLER_TYPE_1","ADT");
		params.put("TRAVELLER_TYPE_2","");
		params.put("TRAVELLER_TYPE_3","");
		params.put("TRAVELLER_TYPE_4","");
		params.put("TRAVELLER_TYPE_5","");
		params.put("TRAVELLER_TYPE_6","");
		params.put("TRAVELLER_TYPE_7","");
		params.put("TRAVELLER_TYPE_8","");
		params.put("TRAVELLER_TYPE_9","");
		params.put("TRIP_TYPE",getTripType());
		params.put("T_Site","CAUOCAUO");
		params.put("agentCode","QEC");
		params.put("date_range","on");
		params.put("homeLoginPageName","/index_cn_chn.jsp");
		params.put("lateLoginPageName","/local/cn/ld/sch/ft/mb/mp_signIn_guest.jsp");
		params.put("ownerCode","QEC");
		params.put("selectedYYYY",goDate[0]);
		params.put("selectedYYYY2",returnDate[0]);
		params.put("serverName","www.koreanair.com");
		params.put("system","kihe");
		params.put("topasURL","http://www.koreanair.com/local/cn/ld/sch/tp/bo/sch_tp_bo_ifr.jsp");
		params.put("v7ResURL","http://wftc3.e-travel.com/plnext/KEREG/Override.action");
		return params;
	}
	
	private Map<String,String> getFTranParams(Map<String,String> params){
		if(params == null){
			params = Maps.newHashMap();
		}
		if(!params.isEmpty()){
			return params;
		}
		String[] goDate = taskQueue.getFlightDate().split("-");
		String[] returnDate = taskQueue.getReturnGrabDate().split("-");
		params.put("AIRLINE_1_1","KE");
		params.put("ARRANGE_BY","N");
		params.put("B_ANY_TIME_1","TRUE");
		params.put("B_ANY_TIME_2","TRUE");
		params.put("B_DATE_1",getRequestDate(taskQueue.getFlightDate()));
		params.put("B_DATE_2",getRequestDate(taskQueue.getReturnGrabDate()));
		params.put("B_DAY",goDate[2]);
		params.put("B_LOCATION_1",taskQueue.getFromCity());
		params.put("B_MONTH",goDate[0] + goDate[1]);
		//params.put("B_REG_ID","CHN");
		params.put("B_TIME","0000");
		params.put("CABIN","");
		params.put("COMMERCIAL_FARE_FAMILY_1","1");
		params.put("DATE_RANGE_VALUE_1","0");
		params.put("DIRECT_LOGIN","NO");
		params.put("EXTERNAL_ID","KE");
		params.put("E_DAY",returnDate[2]);
		params.put("E_LOCATION_1",taskQueue.getToCity());
		params.put("E_MONTH",returnDate[0] + returnDate[1]);
		//params.put("E_REG_ID","JPN");
		params.put("E_TIME","0000");
		params.put("H_Site","CN");
		params.put("LANGUAGE","CN");
		params.put("SERVLET_NAME_KEY","AirAvailability");
		params.put("SESSION_ID","");
		params.put("SEVEN_DAY_SEARCH","TRUE");
		params.put("SITE","CAUOCAUO");
		params.put("SO_SITE_FP_BACKUP_TO_CAL","TRUE");
		params.put("TRAVELLER_TYPE","1");
		params.put("TRAVELLER_TYPE_1","ADT");
		params.put("TRAVELLER_TYPE_2","");
		params.put("TRAVELLER_TYPE_3","");
		params.put("TRAVELLER_TYPE_4","");
		params.put("TRAVELLER_TYPE_5","");
		params.put("TRAVELLER_TYPE_6","");
		params.put("TRAVELLER_TYPE_7","");
		params.put("TRAVELLER_TYPE_8","");
		params.put("TRAVELLER_TYPE_9","");
		params.put("TRIP_TYPE",getTripType());
		params.put("T_Site","CAUOCAUO");
		params.put("agentCode","QEC");
		params.put("homeLoginPageName","/index_cn_chn.jsp");
		params.put("lateLoginPageName","/local/cn/ld/sch/ft/mb/mp_signIn_guest.jsp");
		params.put("ownerCode","QEC");
		params.put("selectedYYYY",goDate[0]);
		params.put("selectedYYYY2",returnDate[0]);
		params.put("serverName","www.koreanair.com");
		params.put("system","kihe");
		params.put("topasURL","http://www.koreanair.com/local/cn/ld/sch/tp/bo/sch_tp_bo_ifr.jsp");
		params.put("v7ResURL","http://wftc3.e-travel.com/plnext/KEREG/Override.action");
		return params;
	}
	
	
	private Map<String,String> getEncParams(Map<String,String> params){
		if(params == null){
			params = Maps.newHashMap();
		}
		if(!params.isEmpty()){
			return params;
		}
		params.put("ARRANGE_BY","E");
		params.put("B_ANY_TIME_1","TRUE");
		params.put("B_ANY_TIME_2","TRUE");
		params.put("B_DATE_1",getRequestDate(taskQueue.getFlightDate()));
		params.put("B_DATE_2",getRequestDate(taskQueue.getReturnGrabDate()));
		params.put("B_LOCATION_1",taskQueue.getFromCity());
		params.put("CABIN","");
		//params.put("COMMERCIAL_FARE_FAMILY_1","PRESTIGE1");
		params.put("DATE_RANGE_QUALIFIER_1","C");
		params.put("DATE_RANGE_QUALIFIER_2","C");
		params.put("DATE_RANGE_VALUE_1","0");
		params.put("DATE_RANGE_VALUE_2","0");
		params.put("DIRECT_LOGIN","NO");
		params.put("DISPLAY_TYPE","2");
		params.put("EMBEDDED_TRANSACTION","FlexPricerAvailability");
		params.put("ENCT","1");
		params.put("EXTERNAL_ID","QEC");
		params.put("E_LOCATION_1",taskQueue.getToCity());
		params.put("FIELD_ADT_NUMBER","1");
		params.put("FIELD_CHD_NUMBER","0");
		params.put("FIELD_INFANTS_NUMBER","0");
		params.put("HAS_INFANT_1","");
		params.put("HAS_INFANT_2","");
		params.put("HAS_INFANT_3","");
		params.put("HAS_INFANT_4","");
		params.put("HAS_INFANT_5","");
		params.put("HAS_INFANT_6","");
		params.put("HAS_INFANT_7","");
		params.put("HAS_INFANT_8","");
		params.put("HAS_INFANT_9","");
		params.put("H_Site","CN");
		params.put("LANGUAGE","CN");
		params.put("PRICING_TYPE","I");
		params.put("SEARCH_PAGE","SD");
		params.put("SESSION_ID","");
		params.put("SEVEN_DAY_SEARCH","TRUE");
		params.put("SITE","CAUOCAUO");
		params.put("SO_GL","");
		params.put("SO_LANG_SITE_AGENCY_LINE1","Korean Air China Service Center(Qingdao)");
		params.put("SO_LANG_SITE_AGENCY_LINE2","TEL) 86-40065-88888");
		params.put("SO_LANG_SITE_AGENCY_LINE3","");
		params.put("SO_LANG_SITE_AGENCY_LINE4","");
		params.put("SO_LANG_SITE_EMAIL_ADDRESS","chinaservicecenter@koreanair.com");
		params.put("SO_QUEUE_OFFICE_ID","SELKE1200");
		params.put("SO_SITE_CLASS_OF_SERVICE","in availability page");
		params.put("SO_SITE_CMP_DATE_IN_GMT","TRUE");
		params.put("SO_SITE_EXT_PSPURL","https://cyb.koreanair.com/iKalApp/cn/int/purchase/chn_paymentProcess.jsp");
		params.put("SO_SITE_FORCE_DDAY_AVAIL","TRUE");
		params.put("SO_SITE_FP_BACKUP_TO_CAL","TRUE");
		params.put("SO_SITE_MAIL_FROM","chinaservicecenter@koreanair.com");
		params.put("SO_SITE_MAIL_REPLY_TO","chinaservicecenter@koreanair.com");
		params.put("SO_SITE_MOD_DELIVERY","FALSE");
		params.put("SO_SITE_MOP_CREDIT_CARD","FALSE");
		params.put("SO_SITE_MOP_EXT","TRUE");
		params.put("SO_SITE_OFFICE_ID","LAXKE18CC");
		params.put("SO_SITE_POINT_OF_SALE","BJS");
		params.put("SO_SITE_POINT_OF_TICKETING","BJS");
		params.put("TRAVELLER_TYPE_1","ADT");
		params.put("TRAVELLER_TYPE_2","");
		params.put("TRAVELLER_TYPE_3","");
		params.put("TRAVELLER_TYPE_4","");
		params.put("TRAVELLER_TYPE_5","");
		params.put("TRAVELLER_TYPE_6","");
		params.put("TRAVELLER_TYPE_7","");
		params.put("TRAVELLER_TYPE_8","");
		params.put("TRAVELLER_TYPE_9","");
		params.put("TRIP_TYPE",getTripType());
		params.put("actionURL","http://www.koreanair.com/local/cn/ld/sch/tp/bo/sch_tp_bo_ifr.jsp");
		params.put("agentCode","QEC");
		params.put("gweb_kal","rkddnjstlr");
		params.put("v7ResURL","http://wftc3.e-travel.com/plnext/KEREG/Override.action");
		return params;
	}
	
	private Map<String,String> getFEncParams(Map<String,String> params){
		if(params == null){
			params = Maps.newHashMap();
		}
		if(!params.isEmpty()){
			return params;
		}
		
		params.put("ARRANGE_BY","E");
		params.put("B_ANY_TIME_1","TRUE");
		params.put("B_ANY_TIME_2","TRUE");
		params.put("B_DATE_1",getRequestDate(taskQueue.getFlightDate()));
		params.put("B_DATE_2",getRequestDate(taskQueue.getReturnGrabDate()));
		params.put("B_LOCATION_1",taskQueue.getFromCity());
		params.put("CABIN","");
		params.put("DIRECT_LOGIN","NO");
		params.put("EMBEDDED_TRANSACTION","AirAvailability");
		params.put("ENCT","1");
		params.put("EXTERNAL_ID","QEC");
		params.put("E_LOCATION_1",taskQueue.getToCity());
		params.put("FIELD_ADT_NUMBER","1");
		params.put("FIELD_CHD_NUMBER","0");
		params.put("FIELD_INFANTS_NUMBER","0");
		params.put("HAS_INFANT_1","");
		params.put("HAS_INFANT_2","");
		params.put("HAS_INFANT_3","");
		params.put("HAS_INFANT_4","");
		params.put("HAS_INFANT_5","");
		params.put("HAS_INFANT_6","");
		params.put("HAS_INFANT_7","");
		params.put("HAS_INFANT_8","");
		params.put("HAS_INFANT_9","");
		params.put("H_Site","CN");
		params.put("LANGUAGE","CN");
		params.put("SEARCH_PAGE","SD");
		params.put("SESSION_ID","");
		params.put("SEVEN_DAY_SEARCH","TRUE");
		params.put("SITE","CAUOCAUO");
		params.put("SO_GL","");
		params.put("SO_LANG_SITE_AGENCY_LINE1","Korean Air China Service Center(Qingdao)");
		params.put("SO_LANG_SITE_AGENCY_LINE2","TEL) 86-40065-88888");
		params.put("SO_LANG_SITE_AGENCY_LINE3","");
		params.put("SO_LANG_SITE_AGENCY_LINE4","");
		params.put("SO_LANG_SITE_EMAIL_ADDRESS","chinaservicecenter@koreanair.com");
		params.put("SO_QUEUE_OFFICE_ID","SELKE1200");
		params.put("SO_SITE_CLASS_OF_SERVICE","in availability page");
		params.put("SO_SITE_EXT_PSPURL","https://cyb.koreanair.com/iKalApp/cn/int/purchase/chn_paymentProcess.jsp");
		params.put("SO_SITE_FP_BACKUP_TO_CAL","TRUE");
		params.put("SO_SITE_MAIL_FROM","chinaservicecenter@koreanair.com");
		params.put("SO_SITE_MAIL_REPLY_TO","chinaservicecenter@koreanair.com");
		params.put("SO_SITE_MOD_DELIVERY","FALSE");
		params.put("SO_SITE_MOP_CREDIT_CARD","FALSE");
		params.put("SO_SITE_MOP_EXT","TRUE");
		params.put("SO_SITE_OFFICE_ID","LAXKE18CC");
		params.put("SO_SITE_POINT_OF_SALE","BJS");
		params.put("SO_SITE_POINT_OF_TICKETING","BJS");
		params.put("TRAVELLER_TYPE_1","ADT");
		params.put("TRAVELLER_TYPE_2","");
		params.put("TRAVELLER_TYPE_3","");
		params.put("TRAVELLER_TYPE_4","");
		params.put("TRAVELLER_TYPE_5","");
		params.put("TRAVELLER_TYPE_6","");
		params.put("TRAVELLER_TYPE_7","");
		params.put("TRAVELLER_TYPE_8","");
		params.put("TRAVELLER_TYPE_9","");
		params.put("TRIP_TYPE",getTripType());
		params.put("actionURL","http://www.koreanair.com/local/cn/ld/sch/tp/bo/sch_tp_bo_ifr.jsp");
		params.put("agentCode","QEC");
		params.put("gweb_kal","rkddnjstlr");
		params.put("v7ResURL","http://wftc3.e-travel.com/plnext/KEREG/Override.action");
		return params;
	}
	
	/**
	 * 获取单程还是往返
	 * @return
	 */
	private String getTripType(){
		if(taskQueue.getIsReturn() == 0){
			return "O";
		}else{
			return "R";
		}
	}
	
	//获取请求日期的格式
	private String getRequestDate(String date){
		return date.replaceAll("\\D", "") + "0000";
	}
	
	/**
	 * 请求不成功切换ip再次请求
	 * @param request 请求
	 * @param time 请求次数
	 * @param keyRegex 错误关键字
	 * @return
	 * @throws Exception
	 */
	private String excute(HttpRequestBase request,int time,String keyRegex) throws Exception{
		String page = null;
		for(int i = 0;i < time;i++){
			try{
				page = excuteRequest(request, interval);
				super.appendPageContents(page);
				if(page.matches(keyRegex)){
					switchProxyipByHttClient();
				}else{
					break;
				}
			}catch(Exception e){
				logger.info("尝试第" +(i+1) + "次抓取失败");
			}
		}
		if(page != null && page.matches(keyRegex)){
			throw new IpBlockException("查询结果跟关键字一致，ip被封");
		}
		return page;
	}
	
	private class FlightInfo{
		private String flightNo;//航班号
		private String startTime;//起飞时间
		private String endTime;//结束时间
		private String fromAirport;//起飞城市机场
		private String toAirport;//到达城市机场
		private String fromAirportName; 
		private String toAirportName;
		private String flightType;//飞机类型
		private Long stopTime;//停留时间
		private Long flightDuration;//飞行总时间
		public String getFlightNo() {
			return flightNo;
		}
		public void setFlightNo(String flightNo) {
			this.flightNo = flightNo;
		}
		public String getStartTime() {
			return startTime;
		}
		public void setStartTime(String startTime) {
			this.startTime = startTime;
		}
		public String getEndTime() {
			return endTime;
		}
		public void setEndTime(String endTime) {
			this.endTime = endTime;
		}
		
		public String getFromAirport() {
			return fromAirport;
		}
		public void setFromAirport(String fromAirport) {
			this.fromAirport = fromAirport;
		}
		public String getToAirport() {
			return toAirport;
		}
		public void setToAirport(String toAirport) {
			this.toAirport = toAirport;
		}
		
		public String getFromAirportName() {
			return fromAirportName;
		}
		public void setFromAirportName(String fromAirportName) {
			this.fromAirportName = fromAirportName;
		}
		public String getToAirportName() {
			return toAirportName;
		}
		public void setToAirportName(String toAirportName) {
			this.toAirportName = toAirportName;
		}
		public String getFlightType() {
			return flightType;
		}
		public void setFlightType(String flightType) {
			this.flightType = flightType;
		}
		public Long getStopTime() {
			return stopTime;
		}
		public void setStopTime(Long stopTime) {
			this.stopTime = stopTime;
		}
		public Long getFlightDuration() {
			return flightDuration;
		}
		public void setFlightDuration(Long flightDuration) {
			this.flightDuration = flightDuration;
		}
		
	}
	
	/**
	 *普通的尝试次数和ip失败关键字 
	 * @param request
	 * @return
	 * @throws Exception
	 */
	private String excute(HttpRequestBase request) throws Exception{
		return excute(request, geneRepeatTime, swapIpRegex);
	}
	
	/**
	 * 验证数据
	 * @param fetchObject
	 * @return
	 * @throws Exception
	 */
	private boolean validateData(Object fetchObject) throws Exception{
		if(fetchObject == null){
			throw new IllegalArgumentException("fetchObject is null");
		}
		//没有航班或座位
		boolean noFlightOrTicket = StringUtil.indexOneOfKeys(fetchObject.toString(), "无法找到指定日期.*相关建议","没有找到.*可搭乘航班","无对应航班或已满","我们无法找到您搜索的结果","我们无法找到相应费用");
		if(noFlightOrTicket){
			throw new FlightInfoNotFoundException("含有无航班或座位关键字");
		}
		return true;
	}
	
	@Override
	public boolean validateFetch(Object fetchObject) throws Exception {
		// TODO Auto-generated method stub
		return true;
	}

	public static void main(String[] args) throws Exception {
		TaskModel taskModel = new TaskModel();
		taskModel.setFromCity("PEK");
		taskModel.setFromCityName("日本");
		taskModel.setToCity("NRT");
		taskModel.setToCityName("东京");
		taskModel.setFlightDate("2014-09-01");
		taskModel.setIsReturn(1);
		taskModel.setIsInternational(1);
		taskModel.setReturnGrabDate("2014-09-06");

		KoreanAirAdapter_bak_1 adapter = new KoreanAirAdapter_bak_1(taskModel);
		Object obj = adapter.fetch(null);
		List<Object> list = adapter.paraseToVo(obj);
		System.out.println(list);
	}
}
